<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Document</title>
</head>
<body>
  <div><h1 id="node-js-">Node.js 模块</h1>
<h2 id="labdoc-header-0">一、实验介绍</h2>
<h3 id="labdoc-header-1">1.1 实验内容</h3>
<p>本次实验对Node.js模块和 Node.js包进行介绍。你将学习如何创建、导入模块，如何创建包和使用npm对包进行管理。</p><h3 id="labdoc-header-2">1.2 实验知识点</h3>
<ul>
<li>Node.js 模块(module)的概念及如何导出和导入模块。 </li>
<li>Node.js 包(package)的创建方法</li>
<li><code>npm</code>包管理工具的使用</li>
</ul>
<h3 id="labdoc-header-3">1.3 实验环境</h3>
<ul>
<li>Xfce终端</li>
<li>Node.js v4.2.1</li>
<li>gedit/vim：文本编辑</li>
</ul>
<h2 id="labdoc-header-4">二、实验步骤</h2>
<h3 id="labdoc-header-5">2.1 Node.js模块(module)</h3>
<p>每一个 Node.js 文件都是一个 Node.js 模块，包括JavaScript文件（.js）、JSON文本文件（.json）和二进制模块文件（.node）。</p><h4 id="2-1-1-">2.1.1 模块的使用</h4>
<p>编写一个模块：</p><p>在虚拟机桌面新建一个文件<code>mymodule.js</code>，输入如下代码并保存：</p><pre><code class="hljs javascript"><span class="hljs-function"><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">function</span></span></span><span class="hljs-function"> </span><span class="hljs-title"><span class="hljs-function"><span class="hljs-title">hello</span></span></span><span class="hljs-function">(</span><span class="hljs-params"></span><span class="hljs-function"><span class="hljs-params"></span>) </span></span>{
    <span class="hljs-built_in"><span class="hljs-built_in">console</span></span>.log(<span class="hljs-string"><span class="hljs-string">'Hello'</span></span>);
}

<span class="hljs-function"><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">function</span></span></span><span class="hljs-function"> </span><span class="hljs-title"><span class="hljs-function"><span class="hljs-title">world</span></span></span><span class="hljs-function">(</span><span class="hljs-params"></span><span class="hljs-function"><span class="hljs-params"></span>) </span></span>{
    <span class="hljs-built_in"><span class="hljs-built_in">console</span></span>.log(<span class="hljs-string"><span class="hljs-string">'World'</span></span>);
}
</code></pre><p>这就是一个Node.js模块，但是怎么在其他模块中引入并使用这个模块呢？我们需要为模块提供对外的接口，这就要用到<code>module.exports</code>和<code>exports</code>。</p><p>我们可以这样写<code>mymodule.js</code>：</p><pre><code class="hljs javascript"><span class="hljs-function"><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">function</span></span></span><span class="hljs-function"> </span><span class="hljs-title"><span class="hljs-function"><span class="hljs-title">hello</span></span></span><span class="hljs-function">(</span><span class="hljs-params"></span><span class="hljs-function"><span class="hljs-params"></span>) </span></span>{
    <span class="hljs-built_in"><span class="hljs-built_in">console</span></span>.log(<span class="hljs-string"><span class="hljs-string">'Hello'</span></span>);
}

<span class="hljs-function"><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">function</span></span></span><span class="hljs-function"> </span><span class="hljs-title"><span class="hljs-function"><span class="hljs-title">world</span></span></span><span class="hljs-function">(</span><span class="hljs-params"></span><span class="hljs-function"><span class="hljs-params"></span>) </span></span>{
    <span class="hljs-built_in"><span class="hljs-built_in">console</span></span>.log(<span class="hljs-string"><span class="hljs-string">'World'</span></span>);
}

exports.hello = hello;
exports.world = world;
</code></pre><p>在其他模块中，可以使用<code>require(module_name);</code>载入需要的模块，如，在虚拟机桌面新建<code>index.js</code>，输入如下代码并保存：</p><pre><code class="hljs ruby">var hello = <span class="hljs-keyword"><span class="hljs-keyword">require</span></span>(<span class="hljs-string"><span class="hljs-string">'./mymodule'</span></span>); <span class="hljs-regexp"><span class="hljs-regexp">//</span></span> 也可以写作 var hello = <span class="hljs-keyword"><span class="hljs-keyword">require</span></span>(<span class="hljs-string"><span class="hljs-string">'./mymodule.js'</span></span>);

<span class="hljs-regexp"><span class="hljs-regexp">//</span></span> 现在就可以使用mymodule.js中的函数了
hello.hello(); <span class="hljs-regexp"><span class="hljs-regexp">//</span></span> <span class="hljs-meta"><span class="hljs-meta">&gt;&gt; </span></span>Hello
hello.world(); <span class="hljs-regexp"><span class="hljs-regexp">//</span></span> <span class="hljs-meta"><span class="hljs-meta">&gt;&gt; </span></span>World
</code></pre><p>也可以这样写<code>mymodule.js</code>：</p><pre><code class="hljs javascript"><span class="hljs-function"><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">function</span></span></span><span class="hljs-function"> </span><span class="hljs-title"><span class="hljs-function"><span class="hljs-title">Hello</span></span></span><span class="hljs-function">(</span><span class="hljs-params"></span><span class="hljs-function"><span class="hljs-params"></span>) </span></span>{
    <span class="hljs-keyword"><span class="hljs-keyword">this</span></span>.hello = <span class="hljs-function"><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">function</span></span></span><span class="hljs-function">(</span><span class="hljs-params"></span><span class="hljs-function"><span class="hljs-params"></span>) </span></span>{
        <span class="hljs-built_in"><span class="hljs-built_in">console</span></span>.log(<span class="hljs-string"><span class="hljs-string">'Hello'</span></span>);
    };

    <span class="hljs-keyword"><span class="hljs-keyword">this</span></span>.world = <span class="hljs-function"><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">function</span></span></span><span class="hljs-function">(</span><span class="hljs-params"></span><span class="hljs-function"><span class="hljs-params"></span>) </span></span>{
        <span class="hljs-built_in"><span class="hljs-built_in">console</span></span>.log(<span class="hljs-string"><span class="hljs-string">'World'</span></span>);
    };
}

<span class="hljs-built_in"><span class="hljs-built_in">module</span></span>.exports = Hello;
</code></pre><p>此时，<code>index.js</code>就要改成这样：</p><pre><code class="hljs ruby">var Hello = <span class="hljs-keyword"><span class="hljs-keyword">require</span></span>(<span class="hljs-string"><span class="hljs-string">'./mymodule'</span></span>);

var hello = new Hello();

hello.hello(); <span class="hljs-regexp"><span class="hljs-regexp">//</span></span> <span class="hljs-meta"><span class="hljs-meta">&gt;&gt; </span></span>Hello
hello.world(); <span class="hljs-regexp"><span class="hljs-regexp">//</span></span> <span class="hljs-meta"><span class="hljs-meta">&gt;&gt; </span></span>World
</code></pre><h4 id="2-1-2-module-exports-exports">2.1.2 module.exports和exports</h4>
<p><code>module</code>是一个对象，每个模块中都有一个<code>module</code>对象，<code>module</code>是对当前模块的一个引用。<code>module.exports</code>对象是由Module系统创建的，而<code>exports</code>可以看作是对<code>module.exports</code>对象的一个引用。在模块中<code>require</code>另一个模块时，以<code>module.exports</code>的值为准，因为有的情况下，<code>module.exports</code>和<code>exports</code>它们的值是不同的。<code>module.exports</code>和<code>exports</code>的关系可以表示成这样：</p><pre><code class="hljs javascript"><span class="hljs-comment"><span class="hljs-comment">// module.exports和exports相同的情况</span></span>
<span class="hljs-keyword"><span class="hljs-keyword">var</span></span> m = {};        <span class="hljs-comment"><span class="hljs-comment">// 表示 module</span></span>
<span class="hljs-keyword"><span class="hljs-keyword">var</span></span> e = m.e = {};  <span class="hljs-comment"><span class="hljs-comment">// e 表示 exports， m.e 表示 module.exports</span></span>

m.e.a = <span class="hljs-number"><span class="hljs-number">5</span></span>;
e.b = <span class="hljs-number"><span class="hljs-number">6</span></span>;

<span class="hljs-built_in"><span class="hljs-built_in">console</span></span>.log(m.e);  <span class="hljs-comment"><span class="hljs-comment">// Object { a: 5, b: 6 }</span></span>
<span class="hljs-built_in"><span class="hljs-built_in">console</span></span>.log(e);    <span class="hljs-comment"><span class="hljs-comment">// Object { a: 5, b: 6 }</span></span>
</code></pre><pre><code class="hljs javascript"><span class="hljs-comment"><span class="hljs-comment">// module.exports和exports不同的情况</span></span>
<span class="hljs-keyword"><span class="hljs-keyword">var</span></span> m = {};        <span class="hljs-comment"><span class="hljs-comment">// 表示 module</span></span>
<span class="hljs-keyword"><span class="hljs-keyword">var</span></span> e = m.e = {};  <span class="hljs-comment"><span class="hljs-comment">// e 表示 exports， m.e 表示 module.exports</span></span>

m.e = { <span class="hljs-attr"><span class="hljs-attr">c</span></span>: <span class="hljs-number"><span class="hljs-number">9</span></span> };    <span class="hljs-comment"><span class="hljs-comment">// m.e（module.exports）引用的对象被修改了</span></span>
e.d = <span class="hljs-number"><span class="hljs-number">10</span></span>;

<span class="hljs-built_in"><span class="hljs-built_in">console</span></span>.log(m.e);  <span class="hljs-comment"><span class="hljs-comment">// Object { c: 9 }</span></span>
<span class="hljs-built_in"><span class="hljs-built_in">console</span></span>.log(e);    <span class="hljs-comment"><span class="hljs-comment">// Object { d: 10 }</span></span>
</code></pre><h3 id="labdoc-header-6">2.2 Node.js包(package)</h3>
<h4 id="2-2-1-">2.2.1 包</h4>
<p>包用于管理多个模块及其依赖关系，可以对多个模块进行封装，包的根目录必须包含<code>package.json</code>文件，<code>package.json</code>文件是CommonJS规范用于描述包的文件，符合CommonJS规范的package.json文件一般包含以下字段：</p><ol>
<li>name：包名。包名是唯一的，只能包含小写字母、数字和下划线。</li>
<li>version：包版本号。</li>
<li>description：包说明。</li>
<li>keywords：关键字数组。用于搜索。</li>
<li>homepage：项目主页。</li>
<li>bugs：提交bug的地址。</li>
<li>license：许可证。</li>
<li>maintainers：维护者数组。</li>
<li>contributors：贡献者数组。</li>
<li>repositories：项目仓库托管地址数组。</li>
<li>dependencies：包依赖。</li>
</ol>
<p>下面是一个<code>package.json</code>示例：</p><pre><code class="hljs json">{
    <span class="hljs-attr"><span class="hljs-attr">"name"</span></span>: <span class="hljs-string"><span class="hljs-string">"bestqd"</span></span>,
    <span class="hljs-attr"><span class="hljs-attr">"description"</span></span>: <span class="hljs-string"><span class="hljs-string">"bestqd test package."</span></span>,
    <span class="hljs-attr"><span class="hljs-attr">"version"</span></span>: <span class="hljs-string"><span class="hljs-string">"0.1.0"</span></span>,
    <span class="hljs-attr"><span class="hljs-attr">"keywords"</span></span>: [
        <span class="hljs-string"><span class="hljs-string">"bestqd"</span></span>,
        <span class="hljs-string"><span class="hljs-string">"nodejs"</span></span>
     ],
    <span class="hljs-attr"><span class="hljs-attr">"maintainers"</span></span>: [{
        <span class="hljs-attr"><span class="hljs-attr">"name"</span></span>: <span class="hljs-string"><span class="hljs-string">"test"</span></span>,
        <span class="hljs-attr"><span class="hljs-attr">"email"</span></span>: <span class="hljs-string"><span class="hljs-string">"test@bestqd.cn"</span></span>
    }],
    <span class="hljs-attr"><span class="hljs-attr">"contributors"</span></span>: [{
        <span class="hljs-attr"><span class="hljs-attr">"name"</span></span>: <span class="hljs-string"><span class="hljs-string">"test"</span></span>,
        <span class="hljs-attr"><span class="hljs-attr">"web"</span></span>: <span class="hljs-string"><span class="hljs-string">"http://www.bestqd.cn/"</span></span>
    }],
    <span class="hljs-attr"><span class="hljs-attr">"bugs"</span></span>: {
        <span class="hljs-attr"><span class="hljs-attr">"mail"</span></span>: <span class="hljs-string"><span class="hljs-string">"test@bestqd.cn"</span></span>,
        <span class="hljs-attr"><span class="hljs-attr">"web"</span></span>: <span class="hljs-string"><span class="hljs-string">"http://www.bestqd.cn/"</span></span>
    },
    <span class="hljs-attr"><span class="hljs-attr">"licenses"</span></span>: [{
        <span class="hljs-attr"><span class="hljs-attr">"type"</span></span>: <span class="hljs-string"><span class="hljs-string">"Apache License v2"</span></span>,
        <span class="hljs-attr"><span class="hljs-attr">"url"</span></span>: <span class="hljs-string"><span class="hljs-string">"http://www.apache.org/licenses/apache2.html"</span></span>
    }],
    <span class="hljs-attr"><span class="hljs-attr">"repositories"</span></span>: [{
        <span class="hljs-attr"><span class="hljs-attr">"type"</span></span>: <span class="hljs-string"><span class="hljs-string">"git"</span></span>,
        <span class="hljs-attr"><span class="hljs-attr">"url"</span></span>: <span class="hljs-string"><span class="hljs-string">"http://github.com/test/test.git"</span></span>
    }],
    <span class="hljs-attr"><span class="hljs-attr">"dependencies"</span></span>: { 
        <span class="hljs-attr"><span class="hljs-attr">"webkit"</span></span>: <span class="hljs-string"><span class="hljs-string">"1.2"</span></span>,
        <span class="hljs-attr"><span class="hljs-attr">"ssl"</span></span>: { 
            <span class="hljs-attr"><span class="hljs-attr">"gnutls"</span></span>: [<span class="hljs-string"><span class="hljs-string">"1.0"</span></span>, <span class="hljs-string"><span class="hljs-string">"2.0"</span></span>],
            <span class="hljs-attr"><span class="hljs-attr">"openssl"</span></span>: <span class="hljs-string"><span class="hljs-string">"0.9.8"</span></span>
        }
    }
}
</code></pre><p><code>package.json</code>文件可以自己手动编辑，但为了方便，更推荐通过<code>npm init</code>命令进行生成。你可以自己尝试在终端中输入<code>npm init</code>命令来生成一个包含<code>package.json</code>文件的包。</p><h4 id="2-2-2-npm-">2.2.2 npm包管理工具</h4>
<p>由于环境网络限制，所以npm命令会连接taobao的源，而不会直接连接官方源。</p><p>npm 也可以从第三方网站（<a href="http://www.npmjs.org/）上下载第三方Node.js包。" target="_blank">http://www.npmjs.org/）上下载第三方Node.js包。</a></p><p>通过npm安装的包会按包名字母顺序出现在<code>package.json</code>中的<code>dependencies</code>字段中。</p><p>在的环境中搜索包（默认会连接到taobao的Node.js源），由于 taobao 的源不支持搜索包，所以需要先设置为官方源：</p><pre><code class="hljs bash"><span class="hljs-symbol">$</span> npm config <span class="hljs-keyword"><span class="hljs-built_in">set</span></span> registry <span class="hljs-comment">https:</span>//<span class="hljs-comment">registry.npmjs.org</span>
</code></pre><p>然后搜索包：</p><pre><code class="hljs bash"><span class="hljs-symbol">$</span> npm search express  <span class="hljs-comment">//搜索express包</span>
</code></pre><p>安装包，如果安装包失败或者比较慢的话可以切换到 taobao 的源：</p><pre><code class="hljs bash"><span class="hljs-symbol">$</span> npm config <span class="hljs-keyword"><span class="hljs-built_in">set</span></span> registry <span class="hljs-comment">https:</span>//<span class="hljs-comment">registry.npm.taobao.org</span>
</code></pre><pre><code class="hljs coffeescript">$ <span class="hljs-built_in"><span class="hljs-built_in">npm</span></span> install -g express  <span class="hljs-regexp"><span class="hljs-regexp">//</span></span>安装包，-g即<span class="hljs-built_in"><span class="hljs-built_in">global</span></span>全局安装
</code></pre><p>更新包：</p><pre><code class="hljs coffeescript"><span class="hljs-meta">$</span><span class="bash"> <span class="hljs-built_in">npm</span> update express</span>
</code></pre><p>卸载包：</p><pre><code class="hljs coffeescript"><span class="hljs-meta">$</span><span class="bash"> <span class="hljs-built_in">npm</span> uninstall express</span>
</code></pre><h2 id="labdoc-header-7">三、实验总结</h2>
<ol>
<li>在Node.js中，每个.js文件都是一个<code>module</code>, module中的对象通过<code>module.exports</code>导出。引用其他module中的对象通过<code>require</code>语句实现。</li>
<li>包含有package.json的一个文件夹是一个Node.js包，Node.js的包依赖管理(搜索、安装、更新、卸载)通过<code>npm</code>完成，通过<code>npm init</code>命令可以在文件夹中初始化一个包。</li>
</ol>
<h2 id="labdoc-header-8">四、课后习题</h2>
<ol>
<li>请你在环境或自己的电脑中使用<code>npm init</code>命令创建一个包</li>
<li>[可选]请你尝试从<code>github</code>或其他网站下载一个别人创建的包，使用npm解决包中的依赖问题。</li>
</ol>
</div>
</body>
</html>